/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import Sound from '@react-native-oh-tpl/react-native-sound';
import {songs, Track} from '../PlayList/model';
import {DeviceEventEmitter} from 'react-native';

class MusicPlayer {
  private playlist: Track[] = [];
  private currentTrackIndex: number = 0;
  private soundInstance: Sound | null = null;
  private isPlaying: boolean = false;
  private progressInterval: NodeJS.Timeout | null = null;
  private onTrackChangeCallback: ((currentTrack: Track) => void) | null = null;
  setOnTrackChange(callback: (currentTrack: Track) => void): void {
    this.onTrackChangeCallback = callback;
  }
  private onStatusChangeCallback: ((isPlaying: boolean) => void) | null = null;
  setOnStatusChange(callback: (isPlaying: boolean) => void): void {
    this.onStatusChangeCallback = callback;
  }

  constructor() {
    this.playlist = songs;
    this.currentTrackIndex = 0;
    this.loadTrack(this.currentTrackIndex);
  }

  private loadTrack(index: number): void {
    if (this.soundInstance) {
      this.soundInstance.release();
    }

    const track = this.playlist[index];
    if (!track) {
      console.warn('Track not found at index', index);
      return;
    }

    this.soundInstance = new Sound(
      track.fileName,
      Sound.MAIN_BUNDLE,
      (error): void => {
        if (error) {
          console.error('Failed to load the track', error);
        }
      },
    );
  }

  play(): void {
    if (!this.soundInstance) {
      return;
    }
    this.soundInstance.play(() => {
      this.currentTrackIndex =
        (this.currentTrackIndex + 1) % this.playlist.length;
      this.loadTrack(this.currentTrackIndex);
      DeviceEventEmitter.emit('trackChange', this.getCurrentTrack());
      setTimeout(() => {
        this.play();
        this.isPlaying = true;
        if (this.onStatusChangeCallback) {
          this.onStatusChangeCallback(this.isPlaying);
        }
        if (this.onTrackChangeCallback) {
          this.onTrackChangeCallback(this.getCurrentTrack()!);
        }
      }, 2000);
    });
    this.isPlaying = true;
    if (this.onStatusChangeCallback) {
      this.onStatusChangeCallback(this.isPlaying);
    }
  }

  pause(): void {
    if (this.soundInstance && this.isPlaying) {
      this.soundInstance.pause();
      this.isPlaying = false;
      if (this.onStatusChangeCallback) {
        this.onStatusChangeCallback(this.isPlaying);
      }
    }
  }

  nextTrack(): void {
    this.currentTrackIndex =
      (this.currentTrackIndex + 1) % this.playlist.length;
    this.isPlaying = true;
    if (this.onStatusChangeCallback) {
      this.onStatusChangeCallback(this.isPlaying);
    }
    this.loadTrack(this.currentTrackIndex);
    if (this.onTrackChangeCallback) {
      this.onTrackChangeCallback(this.getCurrentTrack()!);
    }
    DeviceEventEmitter.emit('trackChange', this.getCurrentTrack());
    setTimeout(() => {
      this.play();
    }, 2000);
  }

  previousTrack(): void {
    this.currentTrackIndex =
      (this.currentTrackIndex - 1 + this.playlist.length) %
      this.playlist.length;
    this.isPlaying = true;
    if (this.onStatusChangeCallback) {
      this.onStatusChangeCallback(this.isPlaying);
    }
    this.loadTrack(this.currentTrackIndex);
    if (this.onTrackChangeCallback) {
      this.onTrackChangeCallback(this.getCurrentTrack()!);
    }
    DeviceEventEmitter.emit('trackChange', this.getCurrentTrack());
    setTimeout(() => {
      this.play();
    }, 2000);
  }

  playTrackByIndex(index: number): void {
    if (index < 0 || index >= this.playlist.length) {
      console.warn('Invalid track index:', index);
      return;
    }
    this.currentTrackIndex = index;
    this.loadTrack(index);
    this.isPlaying = true;
    if (this.onStatusChangeCallback) {
      this.onStatusChangeCallback(this.isPlaying);
    }
    if (this.onTrackChangeCallback) {
      this.onTrackChangeCallback(this.getCurrentTrack()!);
    }
    DeviceEventEmitter.emit('trackChange', this.getCurrentTrack());
    setTimeout(() => {
      this.play();
    }, 2000);
  }

  getCurrentStatus(): boolean {
    return this.isPlaying;
  }

  getCurrentTrack(): Track | null {
    return this.playlist[this.currentTrackIndex] || null;
  }

  setCurrentTime(value: number): void {
    if (this.soundInstance) {
      this.soundInstance.setCurrentTime(value);
    }
  }

  onProgress(callback: (currentTime: number, duration: number) => void): void {
    if (!this.soundInstance) {
      return;
    }

    this.clearProgressInterval();
    this.progressInterval = setInterval(() => {
      this.soundInstance?.getCurrentTime(currentTime => {
        const duration = this.soundInstance?.getDuration() || 0;
        callback(currentTime, duration);
      });
    }, 500);
  }

  private clearProgressInterval(): void {
    if (this.progressInterval) {
      clearInterval(this.progressInterval);
      this.progressInterval = null;
    }
  }

  release(): void {
    this.onTrackChangeCallback = null;
    this.onStatusChangeCallback = null;
  }
}

const musicPlayer = new MusicPlayer();

export default musicPlayer;
